/*
		* Author:	 Sander
		* Date:		 12-apr-2011
		* Name:		 Tracer
		* Version:	1.0
		*
		* This code is property of Sander blahblahblah copyright blahblah.
*/


package javaraytracer;

//PENDING:add function/property description
public class Tracer implements Runnable
{
	public Thread t;

	private JavaRayTracer main;
	private ToneMapper toneMapper;
	private int width;
	private int height;
	private int quality;
	private float qualityRatio;
	private double x_ratio;
	private double y_ratio;
	private Vec3 lastPixel;
	private int skip = 0;

	public Tracer()
	{
		main = JavaRayTracer.instance;
		toneMapper = new ToneMapper();
		width = JavaRayTracer.width;
		height = JavaRayTracer.height;
		quality = JavaRayTracer.quality;
		qualityRatio = JavaRayTracer.qualityRatio;
		x_ratio = main.cam.fov / (double)width;
		y_ratio = (main.cam.fov / (double)height) * ((double)height / (double)width);
	}
	public void run()
	{
		render();
	}

	private void render() //TODO: efficienter maken
	{

		JavaRayTracer.println( "Starting raytracing!" );

		for(int y = 0; y < height; y++)
		{
			for(int x = 0; x < width; x++)
			{
				skip = (x + skip >= width ? width - x - 1 : skip);
				int index = x + y * width;
				
				Vec3 colour = tracePixel( x, height - y );
				
				main.imageSource.pixels[index] = toneMapper.colorMap(colour);
				
				if(lastPixel != null && lastPixel.compare(colour) < 0.05)
				{
					skip += (skip < 2 ? 1 : 0);
					x += skip;
				}
				else if(skip > 0)
				{
					skip = 0;
					colour = tracePixel( x - 1, height - y );
					main.imageSource.pixels[index - 1] = toneMapper.colorMap(colour);
				}
				else
				{
					//it only comes here 1 time. first pixel.
				}
				
				//fills the skipped pixels
				for(int s = 0; s <= skip && x+s <= width; s++)
				{
					main.imageSource.pixels[index + s] = toneMapper.colorMap(colour);
				}
				
				lastPixel = colour;
			}

		}
		JavaRayTracer.println( "Finished Raytracing!" );
		String filename = "images\\" + JavaRayTracer.hour() + "_" + JavaRayTracer.minute() + "_" + JavaRayTracer.second() + "_" + JavaRayTracer.day() + "_" + JavaRayTracer.month() + "_" + JavaRayTracer.year() + ".png";
		main.imageSource.save(filename);
		System.out.println("saved: " + filename);
		main.printTime();
	}

	private Vec3 tracePixel( int x, int y )
	{
		Vec3 sum = new Vec3();

		x -= width / 2;
		y -= height / 2;

		double qualityStep = (Math.PI * 2.0) / (double)quality; //steps for multisampling

		for(int q = 0; q < quality; q++)
		{
			Vec3 direction;
			if(q == 0)
			{
				direction = new Vec3(x * x_ratio, y * y_ratio, 1);
			}
			else
			{
				direction = new Vec3( (x + (Math.cos((double)q * qualityStep)* qualityRatio) ) * x_ratio,
										(y + (Math.sin((double)q * qualityStep) * qualityRatio) ) * y_ratio, 1 );
			}

			direction.normalize();

			Ray r = new Ray( main.cam.origin.add( direction.mul(main.cam.nearPlane) ), direction.rotate(main.cam.rotation) );
			sum = sum.add( r.trace( null, JavaRayTracer.maxReflectionDepth ) );
		}
		sum = sum.div( quality );
		//Utils.clamp(sum, 0.0, 1.0);
		return sum;
	}
}
